/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SLE_CONNECT_MANAGER_H
#define SLE_CONNECT_MANAGER_H

#include <list>
#include <memory>
#include <vector>
#include "refbase.h"
#include "sle_address_parcel.h"
#include "sle_connect_parcel.h"
#include "sle_connect_state_machine.h"
#include "sle_connect_service.h"
#include "sle_device_config.h"
#include "sle_connect_config.h"
#include "sle_utils_base_observer_list.h"
#include "sle_error_code.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
class ISleConnectManagerCallback {
public:
    virtual ~ISleConnectManagerCallback() = default;
    virtual void OnConnectStateChange(uint16_t connectId, const SleAddress &address, SleConnectState state,
        SlePairState pairState, SleDisConnectReason reason) = 0;
    virtual void OnConnectParamUpdateComplete(uint16_t connectId, const SleConnectionParamUpdateEvt &param,
        SleErrorCode errCode) = 0;
    virtual void OnAuthComplete(uint16_t connectId, const SleAddress &address, const SleAuthInfo &info,
        SleErrorCode errCode) = 0;
    virtual void OnPairComplete(uint16_t connectId, const SleAddress &address, SleErrorCode errCode) = 0;
    virtual void OnReadRssiComplete(uint16_t connectId, int8_t rssi, SleErrorCode errCode) = 0;
};

class SleConnectManager {
public:
    static SleConnectManager *GetInstance();
    SleErrorCode Connect(const SleAddress &address) const;
    SleErrorCode Disconnect(const SleAddress &address) const;
    SleErrorCode GetConnectId(const SleAddress &address, uint16_t &connectId) const;
    SleErrorCode GetConnectState(const SleAddress &address, int32_t &state) const;
    SleErrorCode GetConnectDeviceList(std::vector<SleConnectDevice> &devices, uint16_t &number) const;
    SleErrorCode UpdateConnectParam(uint16_t connectId, const SleConnectionParam &param) const;
    SleErrorCode RegisterConnectCallback(ISleConnectManagerCallback &callback) const;
    SleErrorCode UnregisterConnnectCallback(ISleConnectManagerCallback &callback) const;
    SleErrorCode DoConnect(Device &device) const;
    SleErrorCode DoConnectComplete(Device &device, const Message &msg) const;
    SleErrorCode DoDisconnect(Device &device) const;
    SleErrorCode DoDisconnectComplete(Device &device, const Message &msg) const;
    SleErrorCode DoUpdateConnectParam(Device &device, const Message &msg) const;
    void OnConnectStateChange(Device &device, SleConnectState state) const;
    void OnConnectParamUpdateComplete(Device &device) const;

private:
    class SleConnectManagerImpl {
    public:
        class ConnectCallbackImplement : public IConnectCallback {
        public:
            ConnectCallbackImplement(SleConnectManager::SleConnectManagerImpl &impl) : impl_(impl){};
            ~ConnectCallbackImplement() = default;

            void OnConnectStateChange(uint16_t connectId, const SleAddress &address, SleConnectState state,
                SlePairState pairState, SleDisConnectReason reason) override
            {
                impl_.ConnectionInComming(connectId, address, state, pairState, reason);
            }

            void OnConnectParameterUpdate(
                uint16_t connectId, const SleConnectParam &param, SleErrorCode errCode) override
            {
                impl_.ConnectParamReqInComming(connectId, param, errCode);
            }

            void OnConnectParamUpdateComplete(
                uint16_t connectId, const SleConnectionParamUpdateEvt &param, SleErrorCode errCode) override
            {
                impl_.ConnectParamRspInComming(connectId, param, errCode);
            }

            void OnAuthComplete(
                uint16_t connectId, const SleAddress &address, const SleAuthInfo &info, SleErrorCode errCode) override
            {
                impl_.callbacks_.ForEach([connectId, &address, &info, errCode](ISleConnectManagerCallback &callback) {
                    callback.OnAuthComplete(connectId, address, info, errCode);
                });
            }

            void OnPairComplete(uint16_t connectId, const SleAddress &address, SleErrorCode errCode) override
            {
                impl_.callbacks_.ForEach([connectId, &address, errCode](ISleConnectManagerCallback &callback) {
                    callback.OnPairComplete(connectId, address, errCode);
                });
            }

            void OnReadRssiComplete(uint16_t connectId, int8_t rssi, SleErrorCode errCode) override
            {
                impl_.callbacks_.ForEach([connectId, rssi, errCode](ISleConnectManagerCallback &callback) {
                    callback.OnReadRssiComplete(connectId, rssi, errCode);
                });
            }

        private:
            SleConnectManager::SleConnectManagerImpl &impl_;
        };

        SleConnectService *connService_ = nullptr;
        std::unique_ptr<ConnectCallbackImplement> callbackImpl_ = nullptr;
        std::list<std::unique_ptr<Device>> devices_ = {};
        std::mutex lock_;
        SleBaseObserverList<ISleConnectManagerCallback> callbacks_;

        SleErrorCode DoConnect(Device &device);
        SleErrorCode DoConnectComplete(Device &device, const Message &msg);
        SleErrorCode DoDisconnect(Device &device);
        SleErrorCode DoDisconnectComplete(Device &device, const Message &msg);
        SleErrorCode DoUpdateConnectParam(Device &device, const Message &msg);
        Device* FindOrRegister(const SleAddress address);
        Device* FindOrRegister(uint16_t connectId, const SleAddress address);
        Device* FindDevice(const SleAddress address);
        Device* FindDevice(uint16_t connectId);
        void GetConnectDeviceList(std::vector<SleConnectDevice> &devices, uint16_t &number);
        void RemoveDevice(Device &device);
        void ConnectionInComming(uint16_t connectId, const SleAddress &address, SleConnectState state,
            SlePairState pairState, SleDisConnectReason reason);
        void ConnectParamReqInComming(uint16_t connectId, const SleConnectParam &param, SleErrorCode errCode);
        void ConnectParamRspInComming(uint16_t connectId, const SleConnectionParamUpdateEvt &param, SleErrorCode errCode);
        void OnConnectStateChange(Device &device, SleConnectState state);
        void OnConnectParamUpdateComplete(Device &device);

        SleConnectManagerImpl();
        ~SleConnectManagerImpl();
        SLE_DISALLOW_COPY_AND_ASSIGN(SleConnectManagerImpl);
    };
    std::unique_ptr<SleConnectManagerImpl> pimpl_;

    SleConnectManager();
    ~SleConnectManager();
    SLE_DISALLOW_COPY_AND_ASSIGN(SleConnectManager);
};
} // SleStandard
} // NearLink
} // OHOS

#endif // SLE_CONNECT_MANAGER_H
